package cn.anecansaitin.jep;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.util.Objects;

public record Token(TokenType type, String value, int line, int column, int length) {
    // 算术运算符
    public static Token plus(int line, int column) {
        return new Token(TokenType.PLUS, "+", line, column, 1);
    }

    public static Token minus(int line, int column) {
        return new Token(TokenType.MINUS, "-", line, column, 1);
    }

    public static Token multiply(int line, int column) {
        return new Token(TokenType.MULTIPLY, "*", line, column, 1);
    }

    public static Token divide(int line, int column) {
        return new Token(TokenType.DIVIDE, "/", line, column, 1);
    }

    public static Token power(int line, int column) {
        return new Token(TokenType.POWER, "**", line, column, 2);
    }

    public static Token modulo(int line, int column) {
        return new Token(TokenType.MODULO, "%", line, column, 1);
    }

    public static Token inc(int line, int column) {
        return new Token(TokenType.INC, "++", line, column, 2);
    }

    public static Token dec(int line, int column) {
        return new Token(TokenType.DEC, "--", line, column, 2);
    }

    // 位运算符
    public static Token bitLeft(int line, int column) {
        return new Token(TokenType.BIT_LEFT, "<<", line, column, 2);
    }

    public static Token bitRight(int line, int column) {
        return new Token(TokenType.BIT_RIGHT, ">>", line, column, 2);
    }

    public static Token bitRightUnsigned(int line, int column) {
        return new Token(TokenType.BIT_RIGHT_UNSIGNED, ">>>", line, column, 3);
    }

    public static Token bitNot(int line, int column) {
        return new Token(TokenType.BIT_NOT, "~", line, column, 1);
    }

    public static Token bitAnd(int line, int column) {
        return new Token(TokenType.BIT_AND, "&", line, column, 1);
    }

    public static Token bitOr(int line, int column) {
        return new Token(TokenType.BIT_OR, "|", line, column, 1);
    }

    public static Token bitXor(int line, int column) {
        return new Token(TokenType.BIT_XOR, "^", line, column, 1);
    }

    // 关系运算符
    public static Token lessThan(int line, int column) {
        return new Token(TokenType.LESS_THAN, "<", line, column, 1);
    }

    public static Token greaterThan(int line, int column) {
        return new Token(TokenType.GREATER_THAN, ">", line, column, 1);
    }

    public static Token lessThanEqual(int line, int column) {
        return new Token(TokenType.LESS_THAN_EQUAL, "<=", line, column, 2);
    }

    public static Token greaterThanEqual(int line, int column) {
        return new Token(TokenType.GREATER_THAN_EQUAL, ">=", line, column, 2);
    }

    public static Token equal(int line, int column) {
        return new Token(TokenType.EQUAL, "==", line, column, 2);
    }

    public static Token notEqual(int line, int column) {
        return new Token(TokenType.NOT_EQUAL, "!=", line, column, 2);
    }

    // 逻辑运算符
    public static Token and(int line, int column) {
        return new Token(TokenType.AND, "&&", line, column, 2);
    }

    public static Token or(int line, int column) {
        return new Token(TokenType.OR, "||", line, column, 2);
    }

    public static Token not(int line, int column) {
        return new Token(TokenType.NOT, "!", line, column, 1);
    }

    // 赋值运算符
    public static Token assignPlus(int line, int column) {
        return new Token(TokenType.ASSIGN_PLUS, "+=", line, column, 2);
    }

    public static Token assignMinus(int line, int column) {
        return new Token(TokenType.ASSIGN_MINUS, "-=", line, column, 2);
    }

    public static Token assignMultiply(int line, int column) {
        return new Token(TokenType.ASSIGN_MULTIPLY, "*=", line, column, 2);
    }

    public static Token assignDivide(int line, int column) {
        return new Token(TokenType.ASSIGN_DIVIDE, "/=", line, column, 2);
    }

    public static Token assignModulo(int line, int column) {
        return new Token(TokenType.ASSIGN_MODULO, "%=", line, column, 2);
    }

    public static Token assignBitLeft(int line, int column) {
        return new Token(TokenType.ASSIGN_BIT_LEFT, "<<=", line, column, 3);
    }

    public static Token assignBitRight(int line, int column) {
        return new Token(TokenType.ASSIGN_BIT_RIGHT, ">>=", line, column, 3);
    }

    public static Token assignBitAnd(int line, int column) {
        return new Token(TokenType.ASSIGN_BIT_AND, "&=", line, column, 2);
    }

    public static Token assignBitXor(int line, int column) {
        return new Token(TokenType.ASSIGN_BIT_XOR, "^=", line, column, 2);
    }

    public static Token assignBitOr(int line, int column) {
        return new Token(TokenType.ASSIGN_BIT_OR, "|=", line, column, 2);
    }

    // 分隔符和特殊符号
    public static Token leftParen(int line, int column) {
        return new Token(TokenType.LEFT_PAREN, "(", line, column, 1);
    }

    public static Token rightParen(int line, int column) {
        return new Token(TokenType.RIGHT_PAREN, ")", line, column, 1);
    }

    public static Token leftBracket(int line, int column) {
        return new Token(TokenType.LEFT_BRACKET, "[", line, column, 1);
    }

    public static Token rightBracket(int line, int column) {
        return new Token(TokenType.RIGHT_BRACKET, "]", line, column, 1);
    }

    public static Token leftBrace(int line, int column) {
        return new Token(TokenType.LEFT_BRACE, "{", line, column, 1);
    }

    public static Token rightBrace(int line, int column) {
        return new Token(TokenType.RIGHT_BRACE, "}", line, column, 1);
    }

    public static Token dot(int line, int column) {
        return new Token(TokenType.DOT, ".", line, column, 1);
    }

    public static Token unaryMinus(int line, int column) {
        return new Token(TokenType.UNARY_MINUS, "-", line, column, 1);
    }

    public static Token unaryPlus(int line, int column) {
        return new Token(TokenType.UNARY_PLUS, "+", line, column, 1);
    }

    public static Token comma(int line, int column) {
        return new Token(TokenType.COMMA, ",", line, column, 1);
    }

    public static Token assign(int line, int column) {
        return new Token(TokenType.ASSIGN, "=", line, column, 1);
    }

    public static Token semicolon(int line, int column) {
        return new Token(TokenType.SEMICOLON, ";", line, column, 1);
    }

    public static Token colon(int line, int column) {
        return new Token(TokenType.COLON, ":", line, column, 1);
    }

    public static Token question(int line, int column) {
        return new Token(TokenType.QUESTION, "?", line, column, 1);
    }

    // 基本类型关键字
    public static Token shortKeyword(String value, int line, int column) {
        return new Token(TokenType.SHORT, "short", line, column, 5);
    }

    public static Token intKeyword(int line, int column) {
        return new Token(TokenType.INT, "int", line, column, 3);
    }

    public static Token longKeyword(int line, int column) {
        return new Token(TokenType.LONG, "long", line, column, 4);
    }

    public static Token floatKeyword(int line, int column) {
        return new Token(TokenType.FLOAT, "float", line, column, 5);
    }

    public static Token doubleKeyword(int line, int column) {
        return new Token(TokenType.DOUBLE, "double", line, column, 6);
    }

    public static Token byteKeyword(int line, int column) {
        return new Token(TokenType.BYTE, "byte", line, column, 4);
    }

    public static Token charKeyword(int line, int column) {
        return new Token(TokenType.CHAR, "char", line, column, 4);
    }

    public static Token booleanKeyword(int line, int column) {
        return new Token(TokenType.BOOLEAN, "boolean", line, column, 7);
    }

    // 变量引用关键字
    public static Token thisKeyword(int line, int column) {
        return new Token(TokenType.THIS, "this", line, column, 4);
    }

    public static Token superKeyword(int line, int column) {
        return new Token(TokenType.SUPER, "super", line, column, 5);
    }

    public static Token voidKeyword(int line, int column) {
        return new Token(TokenType.VOID, "void", line, column, 4);
    }

    // 流程控制关键字
    public static Token breakKeyword(int line, int column) {
        return new Token(TokenType.BREAK, "break", line, column, 5);
    }

    public static Token caseKeyword(int line, int column) {
        return new Token(TokenType.CASE, "case", line, column, 4);
    }

    public static Token continueKeyword(int line, int column) {
        return new Token(TokenType.CONTINUE, "continue", line, column, 8);
    }

    public static Token elseKeyword(int line, int column) {
        return new Token(TokenType.ELSE, "else", line, column, 4);
    }

    public static Token forKeyword(int line, int column) {
        return new Token(TokenType.FOR, "for", line, column, 3);
    }

    public static Token ifKeyword(int line, int column) {
        return new Token(TokenType.IF, "if", line, column, 2);
    }

    public static Token instanceofKeyword(int line, int column) {
        return new Token(TokenType.INSTANCEOF, "instanceof", line, column, 10);
    }

    public static Token returnKeyword(int line, int column) {
        return new Token(TokenType.RETURN, "return", line, column, 6);
    }

    public static Token switchKeyword(int line, int column) {
        return new Token(TokenType.SWITCH, "switch", line, column, 6);
    }

    public static Token whileKeyword(int line, int column) {
        return new Token(TokenType.WHILE, "while", line, column, 5);
    }

    // 访问控制修饰符
    public static Token publicKeyword(int line, int column) {
        return new Token(TokenType.PUBLIC, "public", line, column, 6);
    }

    public static Token protectedKeyword(int line, int column) {
        return new Token(TokenType.PROTECTED, "protected", line, column, 9);
    }

    public static Token privateKeyword(int line, int column) {
        return new Token(TokenType.PRIVATE, "private", line, column, 7);
    }

    public static Token defaultKeyword(int line, int column) {
        return new Token(TokenType.DEFAULT, "default", line, column, 7);
    }

    // 类、方法和变量修饰符
    public static Token abstractKeyword(int line, int column) {
        return new Token(TokenType.ABSTRACT, "abstract", line, column, 8);
    }

    public static Token classKeyword(int line, int column) {
        return new Token(TokenType.CLASS, "class", line, column, 5);
    }

    public static Token extendsKeyword(int line, int column) {
        return new Token(TokenType.EXTENDS, "extends", line, column, 7);
    }

    public static Token finalKeyword(int line, int column) {
        return new Token(TokenType.FINAL, "final", line, column, 5);
    }

    public static Token implementsKeyword(int line, int column) {
        return new Token(TokenType.IMPLEMENTS, "implements", line, column, 10);
    }

    public static Token interfaceKeyword(int line, int column) {
        return new Token(TokenType.INTERFACE, "interface", line, column, 9);
    }

    public static Token newKeyword(int line, int column) {
        return new Token(TokenType.NEW, "new", line, column, 3);
    }

    public static Token staticKeyword(int line, int column) {
        return new Token(TokenType.STATIC, "static", line, column, 6);
    }

    // 字面量
    public static Token trueLiteral(int line, int column) {
        return new Token(TokenType.TRUE_LITERAL, "true", line, column, 4);
    }

    public static Token falseLiteral(int line, int column) {
        return new Token(TokenType.FALSE_LITERAL, "false", line, column, 5);
    }

    public static Token nullLiteral(int line, int column) {
        return new Token(TokenType.NULL, "null", line, column, 4);
    }

    public static Token intLiteral(String value, int line, int column) {
        return new Token(TokenType.INT_LITERAL, value, line, column, value.length());
    }

    public static Token longLiteral(String value, int line, int column) {
        return new Token(TokenType.LONG_LITERAL, value, line, column, value.length());
    }

    public static Token floatLiteral(String value, int line, int column) {
        return new Token(TokenType.FLOAT_LITERAL, value, line, column, value.length());
    }

    public static Token doubleLiteral(String value, int line, int column) {
        return new Token(TokenType.DOUBLE_LITERAL, value, line, column, value.length());
    }

    public static Token charLiteral(String value, int line, int column) {
        return new Token(TokenType.CHAR_LITERAL, value, line, column, value.length());
    }

    public static Token stringLiteral(String value, int line, int column) {
        return new Token(TokenType.STRING_LITERAL, value, line, column, value.length());
    }

    // 特殊标记
    public static Token eof(int line, int column) {
        return new Token(TokenType.EOF, "eof", line, column, 3);
    }

    public static Token error(int line, int column) {
        return new Token(TokenType.ERROR, "error", line, column, 5);
    }

    public static Token function(String value, int line, int column) {
        return new Token(TokenType.FUNCTION, value, line, column, value.length());
    }

    public static Token identifier(String value, int line, int column) {
        return new Token(TokenType.IDENTIFIER, value, line, column, value.length());
    }

    @Nullable
    public static Token keyword(String value, int line, int column) {
        TokenType keyword = TokenType.getKeyword(value);
        return keyword == null ? null : new Token(keyword, value, line, column, value.length());
    }

    @Nullable
    public static Token innerLiteral(String value, int line, int column) {
        TokenType literal = TokenType.getLiteral(value);
        return literal == null ? null : new Token(literal, value, line, column, value.length());
    }

    @Override
    public @NotNull String toString() {
        return "[" + line + ":" + column + "] Token[" + type + ", '" + value + "'" + "]";
    }

    public String debugToString() {
        return "[" + line + ":" + column + ":" + length + "] Token[" + type + ", '" + value + "'" + "]";
    }
}
